import dgram from 'dgram'
import { WebSocketServer } from 'ws'
import { EventEmitter } from 'events'

export default class DirtRally2 extends EventEmitter {
  private udp = dgram.createSocket('udp4')
  constructor(port: number, version = 5) {
    super()
    this.udp.on('message', data => {
      if (version === 5) {
        this.transport(data)
      }
    })
    this.udp.on('error', console.log)

    this.udp.bind(port, '127.0.0.1', () => console.log(1))
  }

  destroy() {
    this.udp.close()
  }

  private transport(data: Buffer) {
    const dvd = new DataView(data.buffer)
    const dv = new DataView(new ArrayBuffer(84))
    dv.setUint8(0, dvd.getInt32(192, true) & 0xFF) // 1 running   0 menu
    dv.setUint8(1, 0) // Corresponds to EDrivetrainType; 0 = FWD, 1 = RWD, 2 = AWD
    dv.setInt8(2, dvd.getFloat32(33 * 4, true))    // gear
    dv.setUint8(3, dvd.getFloat32(65 * 4, true))                 // max gear
    dv.setFloat32(4, dvd.getFloat32(30 * 4, true), true)  // Steer
    dv.setFloat32(8, dvd.getFloat32(29 * 4, true), true)  // Accel Throttle
    dv.setFloat32(12, dvd.getFloat32(31 * 4, true), true)  // Brake
    dv.setFloat32(16, dvd.getFloat32(32 * 4, true), true)  // Clutch
    dv.setFloat32(20, dvd.getFloat32(28, true), true) // speed 
    dv.setFloat32(24, dvd.getFloat32(64 * 4, true), true) // EngineIdleRpm
    dv.setFloat32(28, dvd.getFloat32(37 * 4, true), true) // CurrentEngineRpm
    dv.setFloat32(32, dvd.getFloat32(63 * 4, true), true) // EngineMaxRpm
    dv.setFloat32(36, -dvd.getFloat32(136, true), true) // g y         max 2 * 9.8
    dv.setFloat32(40, dvd.getFloat32(140, true), true) // g x foword  max 2 * 9.8
    // 方向轴向量
    const rollX = dvd.getFloat32(44, true)
    const rollY = dvd.getFloat32(48, true)
    const rollZ = dvd.getFloat32(52, true)
    // 侧向翻转角度 顺时针为负值
    const ry = Math.atan2(rollY, Math.sqrt(rollX ** 2 + rollZ ** 2))
    dv.setFloat32(44, Math.min(Math.PI, Math.max(-Math.PI, ry)), true) // 侧向翻转角度 顺时针为负值  max PI
    // 侧向轴向量
    const pitchX = dvd.getFloat32(56, true)
    const pitchY = dvd.getFloat32(60, true)
    const pitchZ = dvd.getFloat32(64, true)
    // 前后倾斜角度 后仰为负
    const rx = -Math.atan2(pitchY, Math.sqrt(pitchX ** 2 + pitchZ ** 2))
    dv.setFloat32(48, Math.min(Math.PI, Math.max(-Math.PI, rx)), true) // 前后倾斜角度 后仰为负      max PI
    dv.setFloat32(52, dvd.getFloat32(68, true) / 120, true) // 前左减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(56, dvd.getFloat32(72, true) / 120, true) // 前右减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(60, dvd.getFloat32(76, true) / 120, true) // 后左减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(64, dvd.getFloat32(80, true) / 120, true) // 后右减震变形 -1 ~ 1  正为悬空 即最长
    dv.setFloat32(68, dvd.getFloat32(68, true), true) // 前左减震变形 米 悬空为正
    dv.setFloat32(72, dvd.getFloat32(72, true), true) // 前右减震变形 米 悬空为正
    dv.setFloat32(76, dvd.getFloat32(76, true), true) // 后左减震变形 米 悬空为正
    dv.setFloat32(80, dvd.getFloat32(80, true), true) // 后右减震变形 米 悬空为正
    this.emit('data', dv.buffer)
  }
}